import datetime
import json
import logging
import re

from base.connection import mongodb_util
from base.request import ApiBaseHandler
from common.definition import ret_msg
from conf import config
from helper.api_helper import ApiHelper
from helper.payment.pay_util import generator_trade_no

logger = logging.getLogger("wechat.handlers.dinner")


class CreateParty(ApiBaseHandler):
    async def post(self):
        open_id = await self.get_open_id()
        title = self.get_parameter("title", None)
        content = self.get_parameter("content", None)
        img_urls = self.get_parameter("img_urls", [])
        store_id = int(self.get_parameter("store_id", 0))
        dinner_time = self.get_parameter("dinner_time", None) # 聚餐时间： 格式如 2019-09-17 15:00
        dinner_type = int(self.get_parameter("type", 0))
        nums = int(self.get_parameter("nums", 0))
        fee = round(float(self.get_parameter("fee", 0)), 2)
        name = self.get_parameter("name", None)
        phone = self.get_parameter("phone", None)
        lng = self.get_parameter("lng", None)
        lat = self.get_parameter("lat", None)
        address = self.get_parameter("address", None)
        store_name = self.get_parameter("store_name", None)
        if not title:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数标题"))

        if not content:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数内容"))

        if not dinner_time:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数聚餐时间"))

        if phone and not re.match(r"^1\d{10}$", phone):
            return self.write(ret_msg(code=-1, error_message="手机号码错误"))

        if img_urls:
            if not isinstance(img_urls, list):
                logger.info("type(img_urls)=%s" % type(img_urls))
                img_urls = json.loads(img_urls)

        if len(dinner_time.split(" ")) != 2:
            return self.write(ret_msg(code=-1, error_message="饭局时间格式错误"))

        y_m_d = dinner_time.split(" ")[0] # 年-月-日
        h_m = dinner_time.split(" ")[1] # 时:分
        if len(y_m_d.split("-")) != 3 or len(h_m.split(":")) != 2:
            return self.write(ret_msg(code=-1, error_message="饭局时间格式错误"))

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_agency", "model": Agency},
            {"db_table": "ebt_user_agency", "model": UserAgency},
        ])

        if store_id:
            store = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
            if not store:
                session.close()
                return self.write(ret_msg(code=-1, error_message="餐厅不存在"))
            store_name = store.ebf_agency_name
            address = store.ebf_agency_address
            lng = float(store.ebf_agency_longitude) if store.ebf_agency_longitude else 0
            lat = float(store.ebf_agency_latitude) if store.ebf_agency_latitude else 0
        elif address:
            lng = float(lng) if lng else 0
            lat = float(lat) if lat else 0
        else:
            lng = 0
            lat = 0

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            logger.error(f"用户表无记录: open_id={open_id}")
            session.close()
            return self.write(ret_msg(code=-1, error_message="用户表无记录"))

        headurl = user.ebf_user_headurl
        nickname = user.ebf_user_nickname
        now = datetime.datetime.now()
        user_info = dict(
            open_id=open_id,
            nickname=nickname,
            headurl=headurl
        )
        data = dict(
            _id=generator_trade_no(),  # 饭局ID
            title=title,  # 标题
            content=content,  # 内容
            user=user_info,  # 发帖人信息
            comments=[],  # 评论
            upvotes=[],  # 点赞用户信息
            readers=[],  # 阅读者信息
            joined_user=[user_info], # 已加入饭局的用户信息(发布人默认已加入)
            create_time=now,  # 创建时间
            imgs=img_urls,  # 图片地址列表
            comment_nums=0,  # 评论数
            upvote_nums=0,  # 点赞数
            read_nums=0,  # 阅读人数
            member_nums=1, # 已加入饭局人数
            is_delete=0,  # 是否删除
            agency_id=store_id,  # 餐厅编号
            agency_name=store_name,  # 餐厅名称
            address=address,  # 餐厅地址
            dinner_time=dinner_time, # 饭局时间
            dinner_type=dinner_type, # 饭局类型 (0=表示公开 1=表示私密, 默认0)
            nums=nums, # 饭局预计参加人数
            fee=fee, # 预计人均消费金额
            name=name, # 饭局发布人真实姓名
            phone=phone, # 饭局发布人联系方式
            location=[lng, lat],
            lng=lng,  # 经度
            lat=lat  # 纬度
        )
        try:
            db = mongodb_util.db
            db.sdec_dinner_party.insert(data)
        except Exception as e:
            logger.error(e)
            session.close()
            return self.write(ret_msg(code=-1, error_message="发布失败, 请稍后重试"))

        session.close()
        return self.write(ret_msg())


class Party(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        page_index = int(self.get_argument("page_index", 0))
        page_size = int(self.get_argument("page_size", 10))
        lng = float(self.get_parameter("lng", 0))
        lat = float(self.get_parameter("lat", 0))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        party = []
        try:
            db = mongodb_util.db
            result = db.sdec_dinner_party.aggregate([
                {
                    "$geoNear": {
                        "near": {"type": "Point", "coordinates": [lng, lat]},
                        "distanceField": "distance",
                        "spherical": True
                    }
                },
                {'$match':
                    {
                        "is_delete": 0,
                        "$or": [
                            {"dinner_type": 0},
                            {"dinner_type": 1, "user.open_id": open_id},
                            {
                                "dinner_type": 1,
                                "joined_user": {"$elemMatch": {"open_id": open_id}}
                            },
                        ]
                    }
                },
                {"$sort": {"distance": 1, "create_time": -1}},
                {"$skip": page_start},
                {"$limit": page_size}
            ])
            for p in result:
                p["create_time"] = p["create_time"].strftime("%Y年%m月%d日 %H:%M:%S")
                p["distance"] = round(p["distance"], 2)
                # 判断用户是否已对该饭局点赞
                if open_id in [u["open_id"] for u in p["upvotes"]]:
                    # 已点赞
                    is_upvote = 1
                else:
                    # 未点赞
                    is_upvote = 0

                # 判断用户是否已经加入饭局
                if open_id in [u["open_id"] for u in p["joined_user"]]:
                    # 已加入
                    is_joined = 1
                else:
                    # 未加入
                    is_joined = 0

                # 判断用户是否有删除饭局权限
                if open_id == p["user"]["open_id"] or open_id in config.POSTS_DELETE_PERMISSION:
                    is_delete_permission = 1
                else:
                    is_delete_permission = 0
                p["is_delete_permission"] = is_delete_permission
                p["is_upvote"] = is_upvote
                p["is_joined"] = is_joined
                p.pop("comments")
                p.pop("readers")
                p.pop("upvotes")
                party.append(p)
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="获取饭局列表失败, 请稍后重试"))

        return self.write(ret_msg(data=party))


class UserParty(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        page_index = int(self.get_argument("page_index", 0))
        page_size = int(self.get_argument("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        party = []
        try:
            db = mongodb_util.db
            result = db.sdec_dinner_party.find({
                "is_delete": {"$ne": 1},
                "user.open_id": open_id
            }).sort("_id", -1).skip(page_start).limit(page_size)
            for p in result:
                p["create_time"] = p["create_time"].strftime("%Y年%m月%d日 %H:%M:%S")
                # 判断用户是否对该饭局已点赞
                if open_id in [u["open_id"] for u in p["upvotes"]]:
                    # 已点赞
                    is_upvote = 1
                else:
                    # 未点赞
                    is_upvote = 0

                # 判断用户是否已经加入饭局
                if open_id in [u["open_id"] for u in p["joined_user"]]:
                    # 已加入
                    is_joined = 1
                else:
                    # 未加入
                    is_joined = 0
                p.pop("comments")
                p.pop("readers")
                p.pop("upvotes")
                p["is_delete_permission"] = 1
                p["is_upvote"] = is_upvote
                p["is_joined"] = is_joined
                party.append(p)
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="获取饭局列表失败, 请稍后重试"))

        return self.write(ret_msg(data=party))


class PartyUpvote(ApiBaseHandler):
    async def post(self):
        open_id = await self.get_open_id()
        party_id = self.get_parameter("id", None)
        if not party_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数饭局ID"))

        try:
            db = mongodb_util.db
            result = db.sdec_dinner_party.find_one({"_id": party_id})
            if not result:
                return self.write(ret_msg(code=-1, error_message="饭局ID错误"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            logger.error(f"用户表无记录: open_id={open_id}")
            session.close()
            return self.write(ret_msg(code=-1, error_message="用户表无记录"))

        headurl = user.ebf_user_headurl
        nickname = user.ebf_user_nickname
        user_info = dict(
            open_id=open_id,
            nickname=nickname,
            headurl=headurl
        )
        upvotes = result["upvotes"]
        upvote_nums = result["upvote_nums"]
        if open_id in [u["open_id"] for u in upvotes]:
            # 已点赞
            upvote_index = [u["open_id"] for u in upvotes].index(open_id)
            upvotes.pop(upvote_index)
            upvote_nums -= 1
            is_upvote = 0
        else:
            # 未点赞
            upvotes.append(user_info)
            upvote_nums += 1
            is_upvote = 1

        try:
            db.sdec_dinner_party.update_one(
                {"_id": party_id},
                {"$set": {"upvote_nums": upvote_nums, "upvotes": upvotes}}
            )
        except Exception as e:
            logger.error(e)
            session.close()
            return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        context = dict(upvote_nums=upvote_nums, is_upvote=is_upvote)
        session.close()
        return self.write(ret_msg(data=context))


class PartyJoin(ApiBaseHandler):
    async def post(self):
        open_id = await self.get_open_id()
        party_id = self.get_parameter("id", None)
        if not party_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数饭局ID"))

        try:
            db = mongodb_util.db
            result = db.sdec_dinner_party.find_one({"_id": party_id})
            if not result:
                return self.write(ret_msg(code=-1, error_message="饭局ID错误"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            logger.error(f"用户表无记录: open_id={open_id}")
            session.close()
            return self.write(ret_msg(code=-1, error_message="用户表无记录"))

        headurl = user.ebf_user_headurl
        nickname = user.ebf_user_nickname
        user_info = dict(
            open_id=open_id,
            nickname=nickname,
            headurl=headurl
        )
        joined_user = result["joined_user"]
        member_nums = result.get("member_nums", 0)
        if open_id in [u["open_id"] for u in joined_user]:
            # 已加入
            join_index = [u["open_id"] for u in joined_user].index(open_id)
            joined_user.pop(join_index)
            member_nums -= 1
            is_joined = 0
        else:
            # 未加入
            nums = result["nums"]
            if nums and member_nums >= nums:
                session.close()
                return self.write(ret_msg(code=-1, error_message="已经达到计划聚餐人数，无法加入！"))
            joined_user.append(user_info)
            member_nums += 1
            is_joined = 1

        try:
            db.sdec_dinner_party.update_one(
                {"_id": party_id},
                {"$set": {"member_nums": member_nums, "joined_user": joined_user}}
            )
        except Exception as e:
            logger.error(e)
            session.close()
            return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        context = dict(member_nums=member_nums, is_joined=is_joined, joined_user=joined_user)
        session.close()
        return self.write(ret_msg(data=context))


class CreateComment(ApiBaseHandler):
    async def post(self):
        open_id = await self.get_open_id()
        party_id = self.get_parameter("id", None)
        comment_id = self.get_parameter("comment_id", None)
        content = self.get_parameter("content", None)
        if not party_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数饭局ID"))

        if not content:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数评论内容"))

        try:
            db = mongodb_util.db
            result = db.sdec_dinner_party.find_one({"_id": party_id})
            if not result:
                return self.write(ret_msg(code=-1, error_message="饭局ID错误"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            logger.error(f"用户表无记录: open_id={open_id}")
            session.close()
            return self.write(ret_msg(code=-1, error_message="用户表无记录"))

        comments = result["comments"]
        comment_nums = result["comment_nums"]
        if comment_id:
            comment_index = [c["id"] for c in comments].index(comment_id)
            reply_comment = comments[comment_index]
            if reply_comment["user"]["open_id"] == open_id:
                reply_nickname = None
                reply_id = None
            else:
                reply_nickname = reply_comment["user"]["nickname"]
                reply_id = comment_id
        else:
            reply_nickname = None
            reply_id = None

        headurl = user.ebf_user_headurl
        nickname = user.ebf_user_nickname
        user_info = dict(
            open_id=open_id,
            nickname=nickname,
            headurl=headurl
        )
        comments.append(dict(
            content=content,
            user=user_info,
            id=generator_trade_no(),
            reply_nickname=reply_nickname,
            reply_id=reply_id,
            create_time=datetime.datetime.now()
        ))
        comment_nums += 1
        try:
            db.sdec_dinner_party.update_one(
                {"_id": party_id},
                {"$set": {"comment_nums": comment_nums, "comments": comments}}
            )
        except Exception as e:
            logger.error(e)
            session.close()
            return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        new_comments = []
        for comment in comments[:-11:-1]:
            comment["create_time"] = comment["create_time"].strftime("%Y年%m月%d日 %H:%M:%S")
            new_comments.append(comment)
        context = dict(comment_nums=comment_nums, comments=new_comments)
        session.close()
        return self.write(ret_msg(data=context))


class PartyDetail(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        party_id = self.get_parameter("id", None)
        if not party_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数饭局ID"))

        try:
            db = mongodb_util.db
            result = db.sdec_dinner_party.find_one({"_id": party_id}, {"comments": 0})
            if not result:
                return self.write(ret_msg(code=-1, error_message="饭局ID错误"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        class User(object):
            pass

        session = self.get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            logger.error(f"用户表无记录: open_id={open_id}")
            session.close()
            return self.write(ret_msg(code=-1, error_message="用户表无记录"))

        headurl = user.ebf_user_headurl
        nickname = user.ebf_user_nickname
        user_info = dict(
            open_id=open_id,
            nickname=nickname,
            headurl=headurl
        )
        readers = result.get("readers", [])
        read_nums = result["read_nums"]
        upvotes = result["upvotes"]
        if open_id not in [u["open_id"] for u in readers]:
            # 未阅读
            read_nums += 1  # 阅读量加1
            readers.append(user_info)
            try:
                db.sdec_dinner_party.update_one(
                    {"_id": party_id},
                    {"$set": {"read_nums": read_nums, "readers": readers}}
                )
            except Exception as e:
                logger.error(e)
                session.close()
                return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        # 判断用户是否有删除饭局权限
        if open_id == result["user"]["open_id"] or open_id in config.POSTS_DELETE_PERMISSION:
            is_delete_permission = 1
        else:
            is_delete_permission = 0
        result["is_delete_permission"] = is_delete_permission
        result["read_nums"] = read_nums
        result["create_time"] = result["create_time"].strftime("%Y年%m月%d日 %H:%M:%S")
        if open_id in [u["open_id"] for u in upvotes]:
            is_upvote = 1  # 已点赞
        else:
            is_upvote = 0  # 未点赞

        # 判断用户是否已经加入饭局
        if open_id in [u["open_id"] for u in result["joined_user"]]:
            # 已加入
            is_joined = 1
        else:
            # 未加入
            is_joined = 0
        result["is_upvote"] = is_upvote
        result["is_joined"] = is_joined
        result.pop("upvotes")
        result.pop("readers", None)
        session.close()
        return self.write(ret_msg(data=result))


class PartyComments(ApiBaseHandler):
    async def get(self):
        await self.get_open_id()
        party_id = self.get_parameter("id", None)
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        if not party_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数饭局ID"))

        try:
            db = mongodb_util.db
            results = db.sdec_dinner_party.aggregate([
                {"$match": {"_id": party_id}},
                {"$unwind": "$comments"},
                {"$sort": {"comments.create_time": -1}},
                {"$skip": page_start},
                {"$limit": page_size},
                {"$group": {"_id": "$_id", "comments": {"$push": "$comments"}}}
            ])
            if not results:
                return self.write(ret_msg(code=-1, error_message="饭局ID错误"))
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        context = []
        for r in results:
            comments = r["comments"]
            for c in comments:
                c["create_time"] = c["create_time"].strftime("%Y年%m月%d日 %H:%M:%S")
            context.append(r)

        return self.write(ret_msg(data=context[0] if context else {}))


class DeleteParty(ApiBaseHandler):
    async def post(self):
        open_id = await self.get_open_id()
        party_id = self.get_parameter("id", None)
        if not party_id:
            return self.write(ret_msg(code=-1, error_message="缺少请求参数饭局ID"))

        try:
            db = mongodb_util.db
            party = db.sdec_dinner_party.find_one({"_id": party_id})
            if not party:
                return self.write(ret_msg(code=-1, error_message="饭局不存在!"))

            # 判断用户是否有删除饭局权限
            if open_id != party["user"]["open_id"] and open_id not in config.POSTS_DELETE_PERMISSION:
                return self.write(ret_msg(code=-1, error_message="权限不足!"))
            result = db.sdec_dinner_party.delete_one({"_id": party_id})
            count = result.deleted_count
            logger.info(f"删除的饭局数目: count={count}")
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="删除失败!"))

        return self.write(ret_msg(data=count))


class CreateIndex(ApiBaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        if open_id != "o7qyl0vKx54jB05FjmxNw76SJAPE":
            return self.write(ret_msg(code=-1, error_message="权限不足"))

        try:
            db = mongodb_util.db
            db.sdec_dinner_party.ensure_index([("location", "2dsphere")])  # 创建索引
        except Exception as e:
            logger.error(e)
            return self.write(ret_msg(code=-1, error_message="系统繁忙, 请稍后重试"))

        return self.write(ret_msg())
